#include <string.h>
#include "io/byte_stream.h"
#include "base/logging.h"

ByteStream::ByteStream()
    : size_(0) {
}

ByteStream::~ByteStream() {
  for (Queue::iterator iter = v.begin();
      iter != v.end(); ++iter) {
    delete[] iter->first;
  }
}
  
void ByteStream::Push(const char* buff, int size) {
  char* newbuf = new char[size];
  memcpy(newbuf, buff, size);
  v.push_back(pair<char*, ValidRange>(newbuf, ValidRange(size)));
  size_ += size;
}

void ByteStream::InsertHead(const char* buff, int size) {
  char* newbuf = new char[size];
  memcpy(newbuf, buff, size);
  v.insert(v.begin(), pair<char*, ValidRange>(newbuf, ValidRange(size)));
  size_ += size;
}

void ByteStream::Pop(int size) {
  Pop(NULL, size);
}

void ByteStream::Pop(char* buffer, int size) {
  CHECK(size <= size_);
  int front_size = v.front().second.size();
  if (size < front_size) {
    if (buffer) {
      memcpy(buffer, v.front().first + v.front().second.start, size);
    }
    v.front().second.start += size;
    size_ -= size;
  } else {
    if (buffer) {
      memcpy(buffer, v.front().first + v.front().second.start, front_size);
    }
    delete[] v.front().first;
    v.pop_front();
    size_ -= front_size;
    if (size > front_size) {
      Pop(buffer ? buffer + front_size : NULL, size - front_size);
    }
  }
}

void ByteStream::Peek(char* buffer, int size) {
  CHECK(size <= size_);
  Peek(buffer, size, v.begin());
}

void ByteStream::Peek(char* buffer,
    int size, Queue::const_iterator iter) {
  CHECK(iter != v.end());
  int front_size = iter->second.size();
  if (size <= front_size) {
    memcpy(buffer, iter->first + iter->second.start, size);
  } else {
    memcpy(buffer, iter->first + iter->second.start, front_size);
    Peek(buffer + front_size, size - front_size, iter + 1);
  }
}

int ByteStream::size() {
  return size_;
}

bool ByteStream::PeekInt(int* result) {
  if (size_ < sizeof(int)) return false;
  char buff[sizeof(int)];
  Peek(buff, sizeof(int));
  *result = *((int*) buff);
  return true;
}

bool ByteStream::PeekTwoInt(int* i1, int* i2) {
  int size = sizeof(int) * 2;
  if (size_ < size) return false;
  char buff[size];
  Peek(buff, size);
  *i1 = *((int*) buff);
  *i2 = *((int*) (buff + sizeof(int)));
  return true;
}
  
ValidRange::ValidRange(int size)
    : start(0), end(size) {
}

int ValidRange::size() const {
  return end - start;
}
